package cn.itcast.config;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.annotation.Resource;


@Configuration
@EnableWebSecurity//开启Spring Security的功能
/* prePostEnabled属性决定Spring Security在接口前注解是否可用@PreAuthorize,
@PostAuthorize等注解,设置为true,会拦截加了这些注解的接口 */
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfg extends WebSecurityConfigurerAdapter {

//    @Resource
//    private AuthenticationSuccessHandler loginSuccessHandler; //认证成功结果处理器
//    @Resource
//    private AuthenticationFailureHandler loginFailureHandler; //认证失败结果处理器
    @Autowired
    private SpringSecurityUserService springSecurityUserService;

    //http请求拦截配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        http.headers().frameOptions().disable();//开启运行iframe嵌套页面
        http
                .headers()
                .frameOptions()
                .sameOrigin()
                .and()
                .authorizeRequests()//配置权限
                .antMatchers("/css/**").permitAll()
                .antMatchers("/img/**").permitAll()
                .antMatchers("/pages/login.html").permitAll()
                .antMatchers("/login.html") //修改了 TODO
                .permitAll() // 静态资源无需认证
                .anyRequest()
                .authenticated()                        // 所有请求都需要登录验证
                .and()
                .formLogin()                            //开启formLogin默认配置
                .loginProcessingUrl("/user/login")  //post登录接口，登录验证由系统实现
                .usernameParameter("username")
                .passwordParameter("password")
                .defaultSuccessUrl("/pages/main.html",true)//登录成功跳转接口
                .loginPage("/login.html")
                .permitAll()//请求时未登录跳转接口
                .failureUrl("/login.html")          //用户密码错误跳转接口
                .and()
                .logout()//配置注销
                .logoutUrl("/user/logout")
                .logoutSuccessUrl("/login.html").permitAll()//注销成功跳转接口
                .deleteCookies("myCookie") //删除自定义的cookie
                .and()
                .csrf()
                .disable();// post请求要关闭csrf验证,不然访问报错；实际开发中开启，需要前端配合传递其他参数
//        http//1、配置权限认证
//                .authorizeRequests()
//                .antMatchers("../static/**")
//                .permitAll()
//                //配置不拦截路由
////                .antMatchers("/500").permitAll()
////                .antMatchers("/403").permitAll()
////                .antMatchers("/404").permitAll()
////                .antMatchers("/login").permitAll()
//                .antMatchers("/login.html")
//                .permitAll() // 静态资源无需认证
//                .anyRequest() //任何其它请求
//                .authenticated() //都需要身份认证
//                .and()
//                //2、登录配置表单认证方式
//                .formLogin()
//                .loginPage("/login.html")//自定义登录页面的url
//                .usernameParameter("username")//设置登录账号参数，与表单参数一致
//                .passwordParameter("password")//设置登录密码参数，与表单参数一致
//                // 告诉Spring Security在发送指定路径时处理提交的凭证，默认情况下，将用户重定向回用户来自的页面。登录表单form中action的地址，也就是处理认证请求的路径，
//                // 只要保持表单中action和HttpSecurity里配置的loginProcessingUrl一致就可以了，也不用自己去处理，它不会将请求传递给Spring MVC和您的控制器，所以我们就不需要自己再去写一个/user/login的控制器接口了
//                .successForwardUrl("/pages/main.html")
//                //.defaultSuccessUrl("/page/main.html")//登录成功后默认的跳转页面路径
//                .failureUrl("/login?error=true")
////                .successHandler(loginSuccessHandler)//使用自定义的成功结果处理器
////                .failureHandler(loginFailureHandler)//使用自定义失败的结果处理器
////                .and()
//                //3、注销
////                .logout()
////                .logoutUrl("/logout")
//                //.logoutSuccessHandler(new CustomLogoutSuccessHandler())
////                .permitAll()
////                .and()
//                //4、session管理
////                .sessionManagement()
//               // .invalidSessionUrl("/login") //失效后跳转到登陆页面
//                //单用户登录，如果有一个登录了，同一个用户在其他地方登录将前一个剔除下线
//                //.maximumSessions(1).expiredSessionStrategy(expiredSessionStrategy())
//                //单用户登录，如果有一个登录了，同一个用户在其他地方不能登录
//                //.maximumSessions(1).maxSessionsPreventsLogin(true) ;
//                .and()
//                //5、禁用跨站csrf攻击防御
//                .csrf()
//                .disable();
    }

//    @Override
//    public void configure(WebSecurity web) throws Exception {
//        //配置静态文件不需要认证
//        web.ignoring().antMatchers("/static/**");
//    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                // 从数据库读取的用户进行身份认证
                .userDetailsService(springSecurityUserService)
                .passwordEncoder(passwordEncoder());
    }

    /**
     * 指定加密方式
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        // 使用BCrypt加密密码
        return new BCryptPasswordEncoder();
    }
}
